package org.avapir.snake;

import java.awt.Color;
import java.awt.Graphics;
import java.util.Vector;

/**
 * 
 * @author Alpen Ditrix
 *
 */
public class Snake implements Constants {

	private final class Piece {
		int x;
		int y;

		public Piece(int x, int y) {
			this.x = x;
			this.y = y;
		}

		@Override
		public Object clone() {
			return new Piece(x, y);
		}

		@Override
		public boolean equals(Object p) {
			Piece myHyperPiece;
			try {
				myHyperPiece = (Piece) p;
			} catch (ClassCastException e) {
				return false;
			}
			return myHyperPiece.x == this.x && myHyperPiece.y == this.y;
		}

		@Override
		public String toString() {
			return "(" + Integer.toString(this.x) + ":"
					+ Integer.toString(this.y) + ")";

		}

		private void move(Direction direction) {
			try {
				switch (direction) {
				case RIGHT:
					x += CELL_SIZE;
					break;
				case UP:
					y -= CELL_SIZE;
					break;
				case LEFT:
					x -= CELL_SIZE;
					break;
				case DOWN:
					y += CELL_SIZE;
					break;
				case STOP:
					break;
				default:
					throw new RuntimeException();
				}
			} finally {
				if (x < 0)
					x = Game.game.getWidth() - CELL_SIZE;
				else if (x > Game.game.getWidth() - CELL_SIZE)
					x = 0;
				if (y < 30)
					y = Game.game.getHeight() - CELL_SIZE;
				else if (y > Game.game.getHeight() - CELL_SIZE)
					y = 30;
			}
		}
	}

	public Direction direction;
	private Color headColor, tailColor = Color.white;
	private int myDrillWasCreatedToPierceTheSkies;
	private Vector<Piece> pieces;

	private int score;
	private boolean isAlive;

	public Snake(int x, int y) {
		direction = Direction.STOP;
		isAlive = true;
		pieces = new Vector<Piece>();
		pieces.add(new Piece(x, y));
		pieces.setSize(1);
		pieces.trimToSize();
		score = 0;
		headColor = Color.decode(Integer.toString(this.hashCode()));
		myDrillWasCreatedToPierceTheSkies = 0;
	}

	public Snake(int x, int y, int size) {
		direction = Direction.STOP;
		isAlive = true;
		pieces = new Vector<Piece>();
		for (int i = 0; i < size; i++) {
			pieces.add(new Piece(x, y));
		}
		pieces.setSize(size - 1);
		pieces.trimToSize();
		score = 0;
		headColor = Color.decode(Integer.toString(this.hashCode()));
		myDrillWasCreatedToPierceTheSkies = 0;
	}

	public Direction getDirection() {
		return direction;
	}

	public int getScore() {
		return score;
	}

	public boolean isAlive() {
		return isAlive;
	}

	public int isCovering(int x, int y) {
		for (int i = 0; i < pieces.size(); i++) {
			if (isAlive && pieces.get(i).x == x && pieces.get(i).y == y)
				return i;
		}
		return -1;
	}

	@Override
	public String toString() {
		return pieces.toString();
	}

	private void eat(int i) {
		switch (Game.getFood().get(i).type) {
		case typical:
			grow();
			break;
		case suicide:
			kill();
			break;
		case immediateWin:
			for (Snake s : Game.snakes)
				if (!s.equals(this))
					s.kill();
			break;
		case poison:
			trim();

		}
	}

	private void giveScore(int i) {
		switch (Game.getFood().get(i).type) {
		case immediateWin:
			break;

		}
	}

	private void grow() {
		myDrillWasCreatedToPierceTheSkies++;
	}

	private void kill() {
		isAlive = false;
		setDirection(Direction.STOP);
		Game.aliveSnakesCounter--;
	}

	private void trim() {
		trim(1);
	}

	private void trim(int i) {
		pieces.setSize(pieces.size() - i);
		;
		pieces.trimToSize();
	}

	protected void draw(Graphics g) {

		/* Displays tail */
		if (isAlive)
			g.setColor(tailColor);
		else
			g.setColor(cadavreColor);
		for (int i = pieces.size() - 1; i > 0; i--) {

			try {
				g.fillRect(pieces.get(i).x + CELL_SIZE / 5, pieces.get(i).y
						+ CELL_SIZE / 5, CELL_SIZE * 3 / 5, CELL_SIZE * 3 / 5);
			} catch (NullPointerException e) {
			}
		}

		/* Displays head */
		g.setColor(headColor);
		try {
			g.fillRect(pieces.get(0).x, pieces.get(0).y, CELL_SIZE, CELL_SIZE);
		} catch (NullPointerException e) {
		}
	}

	protected void drawLoser(Graphics g) {
		tailColor = Color.red;
		draw(g);
	}

	protected void drawWinner(Graphics g) {
		tailColor = Color.green;
		draw(g);
	}

	protected void lunch() {
		if (direction != Direction.STOP && isAlive) {
			/* Is snake eats itself? */
			Piece head = pieces.get(0);

			for (int i = 1; i < pieces.size(); i++) {
				if (head.x == pieces.get(i).x && head.y == pieces.get(i).y) {
					System.out.println(i);
					kill();
				}
			}

			/* Is snake eats some food? */
			Vector<Food> food = Game.getFood();
			for (int i = 0; i < food.size(); i++) {
				if (head.x == food.get(i).x && head.y == food.get(i).y) {
					giveScore(i);
					eat(i);
					food.set(i, new Food());
					break;
				}
			}
			/* Is snake eats some another snake? */
			for (Snake s : Game.getSnakes()) {
				if (!s.equals(this)) {
					int res = s.isCovering(head.x, head.y);
					if (res != -1) {
						if (s.isAlive) {
							if (res != 0) {
								int cutted = s.pieces.size() - res;
								s.trim(cutted);
								cutted /= 2;
								myDrillWasCreatedToPierceTheSkies += cutted;
							} else {
								if (pieces.size() > s.pieces.size()) {
									s.kill();
									s.pieces.set(0, null);
								} else {
									kill();
									pieces.set(0, null);
								}
							}
						} else {
							s.pieces.set(res, null);
							myDrillWasCreatedToPierceTheSkies++;
						}
					}
				}
			}
		}
	}

	protected void move() {
		if (direction != Direction.STOP) {
			Piece tail = (Piece) pieces.get(pieces.size() - 1).clone();
			for (int i = pieces.size() - 1; i > 0; i--) {
				pieces.set(i, (Piece) pieces.get(i - 1).clone());
			}
			pieces.get(0).move(direction);

			if (myDrillWasCreatedToPierceTheSkies > 0) {
				pieces.add(tail);
				pieces.trimToSize();
				myDrillWasCreatedToPierceTheSkies--;
			}
		}
	}

	protected Direction setDirection(Direction direction) {
		Direction old = this.direction;
		this.direction = direction;
		return old;
	}

}
